class SceneImage extends PIXI.Container {
	 constructor(gridSize, scene) { 
		super(); 
		
		this.scene = scene;
		this.gridSize = gridSize;
	 }
	 update() {

		var alpha = 1;	
		if(this.scene.player && this.isCylinder)
			if(this.scene.player.x > this.x - 8 && this.scene.player.x < this.x + this.width &&
			   this.scene.player.y > this.y && this.scene.player.y < this.y + this.height - this.gridSize/2)
				alpha = alpha * 0.7;

		this.alpha = alpha;
	 }
	 
	 get centerPoint() {
		 return {x:this.x+this.width/2,y:this.y+this.height-this.gridSize/2};
	 }
	 
	 set centerPoint(val) {
	 	this.x = val.x - this.width/2;
	 	this.y = val.y - this.height+this.gridSize/2;
	 }
}

class Scene extends PIXI.Container {
	constructor() {
		super();
		this.images = [];
	}
	
	update () {
		if(!this.checksum) return;
		
		var blocks = [];
		var gs = this.gridSize;
		
		// 绘制图形
		for(var i = 0; i < this.images.length; i++)
			this.images[i].update();
		
		// 更新实体状态
		for(var i = 0; i < this.children.length; i++) {
			const sprite = this.children[i];
			if(sprite.update) sprite.update();
		}
		
		// 计算圆柱实体Z轴
		this.children.sort((a, b) => 
		{
			if(a.isCylinder && b.isCylinder) {
				var aa = a.centerPoint;
				var bb = b.centerPoint;
				if (aa.y > bb.y) return 1;
				if (aa.y < bb.y) return -1;
				if (aa.x > bb.x) return 1;
				if (aa.x < bb.x) return -1;	
			} 
			
			if(a.isCylinder) return 1;
			if(b.isCylinder) return -1;
			return 0;
		});
		
		// 更新实体动作
		for(var i = 0; i < this.children.length; i++) {			
			var enity = this.children[i];
			if(!enity.isCylinder) 
				continue;
					
			if(enity.action) 
				enity.action.update();
		}
		
		// 如果存在战场则更新战场
		if(this.battle) this.battle.update();
	}

	addChild (child) {
		super.addChild(child);
		child.scene = this;
	}

	/**
	 * 寻路
	 * @param {Object} src 当前坐标
	 * @param {Object} dst 目标坐标
	 */
	findPath(src, dst) {
		var path = this.navmesh.findPath(src, dst);
		if(path) path.splice(0,1);
		return path;
	}
	
	/**
	 * 开启战场
	 * @param {Object} loc 战场开启坐标
	 * @param {Object} radius 战场半径
	 */
	fight(loc, radius) {
		// 首先计算开战时范围内所有角色对主角的敌意
		const enemies = [];
		const childrens = [];
		for(var i = 0; i < this.children.length; i++) {
			const child = this.children[i];
			// 如果子项是圆柱体
			if(child.isCylinder) {
				// 计算与战场距离
				const xDiff = child.x - loc.x;
				const yDiff = child.y - loc.y;
				const distance = Math.sqrt(xDiff * xDiff + yDiff * yDiff);
				// 计算距离是否小于战场半径
				if(distance <= radius) {
					// 如果单位存在敌意则加入到战场敌人列表中
					if(child.isEnemy && child.isEnemy(player) && child != player)
						enemies.push(child);

					// 全部加入子集合以便后续触发战场事件
					childrens.push(child);
				}
			}
		}
		
		// 新建战场
		const battle = new Battle(this, enemies);
		// 触发战场事件
		//for(var i = 0; i < childrens.length; i++)
		//	childrens[i].dispatchEvent(new CustomEvent("battle"), { battle });
			
		// 赋予该场景战场属性
		this.battle = battle;
	}
}

function SceneLoader(loader) {
    this.loader = loader;
} 
SceneLoader.prototype = {
    responseType : 'text',
    load : function(buffer, params, entry) {
        var jsonObj = JSON.parse(buffer);
		entry.checksum = jsonObj.Inculde;
		entry.gridSize = jsonObj.GridSize;
		
		const texture = PIXI.Texture.from(`res/${jsonObj.Inculde}`);
		const columns = jsonObj.BitmapWidth / jsonObj.GridSize;
		// 添加地表
		const tiles = new PIXI.Container();
		tiles.zIndex = -1;
		for(var i = jsonObj.Cells.length - 1; i >= 0; i--) {
		    const cell = jsonObj.Cells[i];
		    const cellX = cell.X * jsonObj.GridSize;
		    const cellY = cell.Y * jsonObj.GridSize;
		    const srcX = (cell.Image % columns) * jsonObj.GridSize + 1;
		    const srcY = Math.floor(cell.Image / columns) * jsonObj.GridSize + 1;
			
			// 绘制贴图 
			const source = new PIXI.Texture(texture,  { x:srcX, y:srcY, width:jsonObj.GridSize-2, height:jsonObj.GridSize-2 });
			const bunny = new PIXI.Sprite(source);
			bunny.x = cellX;
			bunny.y = cellY;
			bunny.width = jsonObj.GridSize;
			bunny.height = jsonObj.GridSize;
			tiles.addChild(bunny);
		}
		entry.addChild(tiles);
				
		// 添加图形组件
		for(var i = 0; i < jsonObj.Images.length; i++) {
			var jsonImg = jsonObj.Images[i];
			const srcX = (jsonImg.Lower % columns) * jsonObj.GridSize;
			const srcY = Math.floor(jsonImg.Lower / columns) * jsonObj.GridSize;
			const dstX = (jsonImg.Upper % columns) * jsonObj.GridSize + jsonObj.GridSize;
			const dstY = Math.floor(jsonImg.Upper / columns) * jsonObj.GridSize + jsonObj.GridSize;
			const width = dstX - srcX;
			const height = dstY - srcY;
			
			var img = new SceneImage(jsonObj.GridSize, entry);
			
			const source = new PIXI.Texture(texture,  { x:srcX + 1, y:srcY + 1, width:width - 2, height:height - 2 });
			const bunny = new PIXI.Sprite(source);
			bunny.width = width;
			bunny.height = height;
			bunny.scale = { x:jsonImg.Transform.ScaleX, y:jsonImg.Transform.ScaleY };
			bunny.angle = jsonImg.Transform.Angle;
			bunny.tint = {r:jsonImg.Color.R,g:jsonImg.Color.G,b:jsonImg.Color.B};
			
			img.x = jsonImg.Transform.X * jsonObj.GridSize;
			img.y = jsonImg.Transform.Y * jsonObj.GridSize;
			img.width = width;
			img.heght = height;
			img.size = width;
			img.alpha = jsonImg.Color.A/255;
			img.isCylinder = jsonImg.IsCylinder;	
			img.addChild(bunny);
			entry.addChild(img);
		}
		
		// 添加npc组件
		for(var i = 0; i < jsonObj.Npcs.length; i++) {
			var jsonNpc = jsonObj.Npcs[i];
			// 加载NPC脚本
			window.require(jsonNpc.Script);
			// 新建NPC
			var npc = L2D.Loader.load(`res/${jsonNpc.Style}`);
			// 为NPC添加动作
			npc.state = `idea`;
			// 为npcs设置坐标等信息
			npc.x = jsonNpc.Transform.X * jsonObj.GridSize;
			npc.y = jsonNpc.Transform.Y * jsonObj.GridSize;
			npc.scale = { x:jsonNpc.Transform.ScaleX, y:jsonNpc.Transform.ScaleY };
			npc.angle = jsonNpc.Transform.Angle;
			npc.tint = {r:jsonNpc.Color.R,g:jsonNpc.Color.G,b:jsonNpc.Color.B};
			npc.isCylinder = true;
			npc.uuid = jsonNpc.Wid;
			npc.name = jsonNpc.Header;
			// 添加到实体组件内
			entry.addChild(npc);
		}

		// 添加阻挡区域
		var meshPolygonPoints = [];
		var blocks = [];
		for(var yy = 0; yy < jsonObj.GridMap.length; yy++) {
			const row = jsonObj.GridMap[yy];
			for(var xx = 0; xx < row.length; xx++) {
				const x = yy*entry.gridSize;
				const y = xx*entry.gridSize;
				const w = entry.gridSize;
				const h = entry.gridSize;
					
				if(row[xx]) 
					meshPolygonPoints.push([{x,y},{x:x+w,y},{x:x+w,y:y+h},{x,y:y+h}]);
				else
					blocks.push({x,y,width:w,height:h});
			}
		}
		entry.blocks = blocks;
		entry.navmesh = new NavMesh(meshPolygonPoints);
    },
	create : function() {
	    return new Scene();  
	}
};

L2D.Loader.addMode("gat", new SceneLoader(this));